#include <iostream>
#include <pthread.h>
#include <vector>
#include <queue>
#include "Task.hpp"
const int defaultpoll_num = 6;

// 实现一个线程池

class ThreadData
{
public:
    ThreadData()
    {
    }

public:
    pthread_t pid_;
    std::string thname_;
};

class ThreadPoll
{
    bool QueueEmpty()
    {
        return tasks_.empty();
    }
    void Wait()
    {
        pthread_cond_wait(&cond_, &lock_);
    }
    void Lock(pthread_mutex_t& lock_)
    {
        pthread_mutex_lock(&lock_);
    }
    void Unlock(pthread_mutex_t& lock_)
    {
        pthread_mutex_unlock(&lock_);
    }

    Task Pop()
    {
        Task ret = tasks_.front();
        tasks_.pop();
        return ret;
    }

    void WakeUp()
    {
        pthread_cond_signal(&cond_);
    }

    std::string GetThreadName(pthread_t pid)
    {
        for (auto &td : thpoll_)
            if (td->pid_ == pid)
                return td->thname_;

        return "None";
    }

    static void *HanlderTask(void *args)
    {
        ThreadPoll *tp_ = (ThreadPoll *)args;
        std::string name = tp_->GetThreadName(pthread_self());
        while (true)
        {
            // 1. 先加锁
            tp_->Lock(tp_ -> lock_);
            // 2.判断资源是否足够 , 不够进入条件变量中等待
            while (tp_->QueueEmpty())
                tp_->Wait();

            Task tk = tp_->Pop();
            tp_->Unlock(tp_ -> lock_);

            // 3. 让线程处理任务
            std::cout << name;
            tk();
        }

        return nullptr;
    }

    ThreadPoll(const int poll_num = defaultpoll_num)
    {
        // 初始化锁和条件变量 , 为线程池开空间
        pthread_mutex_init(&lock_, nullptr);
        pthread_cond_init(&cond_, nullptr);

        thpoll_.resize(poll_num);
    }

    ~ThreadPoll()
    {
        pthread_mutex_destroy(&lock_);
        pthread_cond_destroy(&cond_);
    }

public:
    void Start()
    {
        // 开始创建线程池
        for (int i = 0; i < thpoll_.size(); i++)
        {
            thpoll_[i] = new ThreadData;
            thpoll_[i]->thname_ = "pthread-" + std::to_string(i + 1);
            pthread_create(&(thpoll_[i]->pid_), nullptr, HanlderTask, this);
        }
    }

    void Push(const Task &tk)
    {
        // 先上锁 , 再插入 , 最后唤醒

        Lock(lock_);
        tasks_.push(tk);
        WakeUp();
        Unlock(lock_);
    }

    static ThreadPoll* GetThreadPoll()
    {
        if(tp_ == nullptr)
        {
            pthread_mutex_lock(&tlock_);
            if(tp_ == nullptr)
            {
                tp_ = new ThreadPoll;
            }
            pthread_mutex_unlock(&tlock_);
        }
        return tp_;
    }

private:
    std::vector<ThreadData *> thpoll_; // 线程池
    std::queue<Task> tasks_;           // 任务队列
    pthread_mutex_t lock_;             // 锁
    pthread_cond_t cond_;              // 条件变量

    static ThreadPoll *tp_;        // 设置为单例模式
    static pthread_mutex_t tlock_; // 作为创建单例模式时的锁
};

ThreadPoll *ThreadPoll::tp_ = nullptr;
pthread_mutex_t ThreadPoll::tlock_ = PTHREAD_MUTEX_INITIALIZER;
